package net.aiion.weave.impl.cards.expressions;

import java.util.ArrayList;
import java.util.Collection;

import net.aiion.weave.spi.bytecode.Bytecode;
import net.aiion.weave.spi.cards.CardException;
import net.aiion.weave.spi.cards.expressions.CardExpression;
import net.aiion.weave.spi.cards.expressions.CardExpressionResolver;
import net.aiion.weave.spi.cards.expressions.CardExpressionResolverService;
import net.aiion.weave.spi.injection.annotations.Inject;
import net.aiion.weave.spi.naming.UserContext;
import net.aiion.weave.spi.naming.annotations.Bound;
import net.aiion.weave.spi.naming.annotations.Named;
import net.aiion.weave.spi.naming.annotations.UserScoped;

@UserScoped
@Named
public class CardExpressionResolverServiceImpl implements CardExpressionResolverService {
    private final Collection<CardExpressionResolver> cardExpressionResolvers;

    @Inject
    private UserContext userContext;

    public CardExpressionResolverServiceImpl() {
        cardExpressionResolvers = new ArrayList<>();
    }

    @Bound
    public void initializeExpressionProcessor() {
        for (Class<? extends CardExpressionResolver> cardExpressionResolverClass : Bytecode
            .findClassesByInterfaceClass(CardExpressionResolver.class)) {
            cardExpressionResolvers.add(userContext.lookup(cardExpressionResolverClass));
        }
    }

    @Override
    public Object readExpression(final String aExpressionPrefix, final String aExpressionValue) {
        return readExpression(createExpression(aExpressionPrefix, aExpressionValue));
    }

    @Override
    public Object readExpression(final CardExpression aCardExpression) {
        return findExpressionResolver(aCardExpression).readExpression(aCardExpression);
    }

    @Override
    public void writeExpression(final String aExpressionPrefix, final String aExpressionValue, final Object aValue) {
        writeExpression(createExpression(aExpressionPrefix, aExpressionValue), aValue);
    }

    @Override
    public void writeExpression(final CardExpression aCardExpression, final Object aValue) {
        findExpressionResolver(aCardExpression).writeExpression(aCardExpression, aValue);
    }

    private CardExpression createExpression(final String aPrefix, final String aValue) {
        return new CardExpressionImpl(aPrefix, aValue);
    }

    private CardExpressionResolver findExpressionResolver(final CardExpression aCardExpression) {
        for (CardExpressionResolver cardExpressionResolver : cardExpressionResolvers) {
            if (cardExpressionResolver.resolvesExpression(aCardExpression)) {
                return cardExpressionResolver;
            }
        }

        throw new CardException("Cannot find a CardExpressionResolver for expression '" + aCardExpression + "'");
    }
}
